package cn.qayy.service.impl;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import cn.qayy.constants.Constant;
import cn.qayy.dao.PolicyMapper;
import cn.qayy.dto.Msg;
import cn.qayy.dto.PolicyDTO;
import cn.qayy.dto.QueryVO;
import cn.qayy.po.Bid;
import cn.qayy.po.Plan;
import cn.qayy.po.Policy;
import cn.qayy.po.Standard;
import cn.qayy.service.IBidService;
import cn.qayy.service.IPlanService;
import cn.qayy.service.IPolicyLogService;
import cn.qayy.service.IPolicyService;
import cn.qayy.service.IStandardService;
import cn.qayy.service.Uploadable;
import cn.qayy.utils.ArithUtil;
import cn.qayy.utils.DateUtils;
import cn.qayy.utils.DownLoadUtil;
import cn.qayy.utils.InitPlansUtil;
import cn.qayy.utils.ServletContextUtils;
import cn.qayy.utils.StringUtil;

/***
 * @author wy
 *
 */
@Service("policyServiceImpl")
@SuppressWarnings("all")
public class PolicyServiceImpl implements IPolicyService {
	private Logger logger = LoggerFactory.getLogger(PolicyServiceImpl.class);
	@Resource
	private PolicyMapper policyMapper;
	
	@Resource(name = "bidServiceImpl")
	private IBidService iBidService;

	@Resource(name = "standardServiceImpl")
	private IStandardService iStandardService;
	
	@Resource(name = "planServiceImpl")
	private IPlanService planService;
	
	@Resource(name = "policyLogServiceImpl")
	private IPolicyLogService policyLogService;

	@Override
	public PageInfo<Map<String, Object>> selectPolicyBy(Map<String, Object> params) {
		if (params != null && params.size() >= 0) {
			DownLoadUtil.set("PolicyDTO",params);
			if (params.containsKey("pageNumber") && params.containsKey("pageSize")) {
				Integer pageNum = Integer.parseInt((String) params.get("pageNumber"));
				Integer pageSize = Integer.parseInt((String) params.get("pageSize"));
				PageHelper.startPage(pageNum, pageSize);
			}
			List<Map<String, Object>> list = policyMapper.selectPolicyBy(params);
			PageInfo<Map<String, Object>> pageInfo = new PageInfo<Map<String, Object>>(list);
			return pageInfo;
		}
		return null;
	}

	@Override
	public int insertByList(List forList) {
		return policyMapper.insertByList(forList);
	}

	@Override
	public Policy selectPolicyByID(@RequestParam Integer planId) {
		return policyMapper.selectByPrimaryKey(planId);
	}

	@Override
	public List<? extends String> selectPolicyKeys() {
		return policyMapper.selectPolicyKeys();
	}

	@Override
	public int updateByList(List list) {
		return policyMapper.updateByList(list);
	}

	@Override
	public int deleteByList(List list) {
		return policyMapper.deleteByList(list);
	}

	@Override
	public int insert(Object bean) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int update(Object bean) {
		return policyMapper.updateByPrimaryKeySelective(bean);
	}

	@Override
	public int delete(Object bean) {
		return policyMapper.delete(bean);
	}

	@Override
	public List<Policy> selectPolicys(Map<String, Object> params) {
		return policyMapper.selectPolicys(params);
	}

	@Override
	public List<Policy> selectByMap(Map<String, Object> params) {
		return policyMapper.selectByMap(params);
	}

	@Override
	public List<Integer> selectIdsByMap(Map<String, Object> params) {
		return policyMapper.selectIdsByMap(params);
	}
	@Override
	public int checkRe(Policy p) {
		return policyMapper.checkRe(p);
	}

	@Override
	public void persistence(Map<String, List<Uploadable>> map, HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		// 更新
		List<Uploadable> listE = map.get("E");
		if (listE != null && !listE.isEmpty()) {
			//获取查询条件，目的为了查询和该协议先关联的流向
			Set<String> yifan_parmas = new HashSet<String>();
			Set<String> product_parmas = new HashSet<String>();
			Set<String> pack_parmas = new HashSet<String>();
			
			// 待更新的实体list
			List<Policy> list = new ArrayList<Policy>(listE.size() + 1);
			List<Policy> db_list = new ArrayList<Policy>(listE.size()+1);
			List<String> ids = new ArrayList<String>(listE.size()+1);
			for (Uploadable u : listE) {
				PolicyDTO dto = (PolicyDTO)u;
				ids.add(dto.getId());
			}
			db_list = policyMapper.selectByIds(ids);
			//校验Excel上传的id是否正确
			if(ids.size() != db_list.size()) {
				throw new Exception(Constant.FAIL_MSG_ID);
			}
			
			//需要缓存的、需要移除缓存的
			List<Policy> plist = new ArrayList<Policy>();
			
			for (Uploadable u : listE) {
				PolicyDTO dto = (PolicyDTO) u;
				for(Policy p:db_list) {
					if(p.getId().toString().equals(dto.getId())) {
						//当前待修改的协议，移除缓存
						plist.add(p);
						//初始化协议
						initPolicy(p, dto, request, true);
						list.add(p);
						//参数初始化
						yifan_parmas.add(p.getQsterminal());
						product_parmas.add(p.getProduct());
						pack_parmas.add(p.getPage());
						continue;
					}
				}
			}
			if(!list.isEmpty()) {
				//修改前的协议，移除缓存
				removeToContext(plist);
				try {
					request.setAttribute("logAction", "E");
					policyLogService.insertByList(list, request);
					policyMapper.updateByList(list);
				} catch (Exception e) {
					addToContext(plist);
					throw e;
				}
				//修改后的协议，添加context缓存
				addToContext(list);
				//协议持久化后，同步更新非毕流向
				syncPlans(list,yifan_parmas,product_parmas,pack_parmas);
			}
		}

		// 不是真正的删除，后台执行修改，修改成3状态表示该协议废弃
		List<Uploadable> listD = map.get("D");
		if (listD != null && !listD.isEmpty()) {
			//获取查询条件，目的为了查询和该协议先关联的流向
			Set<String> yifan_parmas = new HashSet<String>();
			Set<String> product_parmas = new HashSet<String>();
			Set<String> pack_parmas = new HashSet<String>();
			
			// 待删除的实体list
			List<Policy> list = new ArrayList<Policy>(listD.size() + 1);
			List<Policy> db_list = new ArrayList<Policy>(listE.size()+1);
			List<String> ids = new ArrayList<String>(listE.size()+1);
			for (Uploadable u : listD) {
				PolicyDTO dto = (PolicyDTO)u;
				ids.add(dto.getId());
			}
			db_list = policyMapper.selectByIds(ids);
			//校验Excel上传的id是否正确
			if(ids.size() != db_list.size()) {
				throw new Exception(Constant.FAIL_MSG_ID);
			}
			
			//需要缓存的、需要移除缓存的
			List<Policy> plist = new ArrayList<Policy>();
			
			for (Uploadable u : listD) {
				PolicyDTO dto = (PolicyDTO) u;
				for(Policy p:db_list) {
					if(p.getId().toString().equals(dto.getId())) {
						plist.add(p);
						//初始化协议
						initPolicy(p, dto, request, true);
						list.add(p);
						//参数初始化
						yifan_parmas.add(p.getQsterminal());
						product_parmas.add(p.getProduct());
						pack_parmas.add(p.getPage());
						continue;
					}
				}
			}
			if(!list.isEmpty()) {
				try {
					removeToContext(plist);
					request.setAttribute("logAction", "D");
					policyLogService.insertByList(list, request);
					policyMapper.deleteByList(list);
				} catch (Exception e) {
					removeToContext(plist);
					throw e;
				}
				// 更新context缓存
				removeToContext(list);
				
				//协议持久化后，同步更新非毕流向
				syncPlans(list,yifan_parmas,product_parmas,pack_parmas);
			}
		}

		List<Uploadable> listN = map.get("N");
		if (listN != null && !listN.isEmpty()) {
			//获取查询条件，目的为了查询和该协议先关联的流向
			Set<String> yifan_parmas = new HashSet<String>();
			Set<String> product_parmas = new HashSet<String>();
			Set<String> pack_parmas = new HashSet<String>();
			
			// 待新增的实体list
			List<Policy> list = new ArrayList<Policy>(listN.size() + 1);
			for (Uploadable u : listN) {
				PolicyDTO dto = (PolicyDTO) u;
				Policy p = new Policy();
				initPolicy(p, dto, request, false);
				list.add(p);
				yifan_parmas.add(p.getQsterminal());
				product_parmas.add(p.getProduct());
				pack_parmas.add(p.getPage());
			}
			if(!list.isEmpty()) {
				policyMapper.insertByList(list);
				// 更新context缓存
				addToContext(list);
				
				//协议持久化后，同步更新流向
				syncPlans(list,yifan_parmas,product_parmas,pack_parmas);
			}
		}
	}
	
	/***
	 * 协议持久化后，同步更新流向
	 * @param list
	 * @param yifan_parmas
	 * @param product_parmas
	 * @param pack_parmas
	 * @throws Exception
	 */
	private void syncPlans(List<Policy> list,Set<String> yifan_parmas,Set<String> product_parmas,Set<String> pack_parmas) throws Exception {
		if(list!=null && !list.isEmpty()) {
			Map<String, Object> params = new HashMap<String,Object>();
			params.put("terminals", yifan_parmas);
			params.put("products", product_parmas);
			params.put("packs", pack_parmas);
			List<Plan> list2 = planService.selectByMap(params);
			//list:协议list,list2：流向list
			if(list2 != null && !list2.isEmpty()) {
				InitPlansUtil.policysInitPlan(list,null,list2);
				planService.updateByList(list2);
			}
		}
	}
	/***
	 * 通过协议ID，查询对应流向，同步更新
	 * @param list
	 * @throws Exception
	 */
	private void syncPlans(List<Policy> list) throws Exception {
		if(list!=null && !list.isEmpty()) {
			Map<String, Object> params = new HashMap<String,Object>();
			List<Integer> policyIds = new ArrayList<Integer>();
			for (Policy policy : list) {
				policyIds.add(policy.getId());
			}
			params.put("policyIds", policyIds);
			List<Plan> list2 = planService.selectByMap(params);
			//list:协议list,list2：流向list
			if(list2 != null && !list2.isEmpty()) {
				InitPlansUtil.policysInitPlan(list,null,list2);
				planService.updateByList(list2);
			}
		}
	}
	
	/***
	 * 持久化中标库后，更新context缓存
	 * 
	 * @param list
	 */
	private void addToContext(List<Policy> list) {
		/***
		 * 获取项目上下文的共享数据
		 */
		ServletContext servletContext = ServletContextUtils.getServletContext();
		// 协议keys
		Set<String> policyKeys = (Set<String>) servletContext.getAttribute("policyKeys");
		for (Policy b : list) {
			policyKeys.add(StringUtil.concatDaohao(b.getProduct(), b.getPage(), 
					b.getQsterminal(),b.getXieyistarttime(),b.getXieyiendtime()+ ""));
		}
	}
	/***
	 * 持久化中标库后，更新context缓存
	 * 
	 * @param list
	 */
	private void removeToContext(List<Policy> list) {
		/***
		 * 获取项目上下文的共享数据
		 */
		ServletContext servletContext = ServletContextUtils.getServletContext();
		// 协议keys
		Set<String> policyKeys = (Set<String>) servletContext.getAttribute("policyKeys");
		for (Policy b : list) {
			policyKeys.remove(StringUtil.concatDaohao(b.getProduct(), b.getPage(), 
					b.getQsterminal(),b.getXieyistarttime(),b.getXieyiendtime() + ""));
		}
	}
	/***
	 * 中标价初始化
	 * @param p
	 * @return
	 * @throws Exception
	 */
	private Bid bidInit(Policy p) throws Exception{
		Bid bid = null;
		//OTC条线，中标价为0
		if(Constant.TX_OTC.equals(p.getQudaolie())) {
			p.setZhongbiaojia("0");
		} else {
			//Rx条线，中标价参考中标库
			Map<String,Object> params = new HashMap<String,Object>();
			//先完整匹配
			params.put("province", p.getProvince());
			params.put("city", p.getCity());
			params.put("terminal", p.getQsterminal());
			params.put("product", p.getProduct());
			params.put("pack", p.getPage());
			params.put("stime", p.getXieyistarttime());
			params.put("etime", p.getXieyiendtime());
			bid = iBidService.getBid(params);
			if (bid == null) {
				//没找到，入货乙方特殊条件
				params = new HashMap<String,Object>();
				params.put("province", p.getProvince());
				params.put("terminal", p.getQsterminal());
				params.put("product", p.getProduct());
				params.put("pack", p.getPage());
				params.put("stime", p.getXieyistarttime());
				params.put("etime", p.getXieyiendtime());
				bid = iBidService.getBid(params);
				if (bid == null) {
					//没找到，则放开入货乙方条件寻找
					params = new HashMap<String,Object>();
					params.put("province", p.getProvince());
					params.put("city", p.getCity());
					params.put("product", p.getProduct());
					params.put("pack", p.getPage());
					params.put("stime", p.getXieyistarttime());
					params.put("etime", p.getXieyiendtime());
					bid = iBidService.getBid(params);
					if (bid == null) {
						//没找到，则放开入货乙方、地市 条件寻找
						params = new HashMap<String,Object>();
						params.put("province", p.getProvince());
						params.put("product", p.getProduct());
						params.put("pack", p.getPage());
						params.put("stime", p.getXieyistarttime());
						params.put("etime", p.getXieyiendtime());
						bid = iBidService.getBid(params);
						if (bid == null) {
							/**
							 * 中标价验证不通过，前台提示消息 
							 */
							Msg msg = new Msg(Constant.FAIL_CODE, 
									"省份：【"+p.getProvince()+"】，地市：【"+p.getCity()+"】，"
									 + "入货乙方：【"+p.getQsterminal()+"】，品种：【"+p.getProduct()+"】，"
									 + "包装：【"+p.getPage()+"】，开始时间：【"+p.getXieyistarttime()+"】，"
									 + "结束时间：【"+p.getXieyiendtime()+"】，未找到对应的中标价，请核查【中标库】");
							throw new Exception(msg.toString());
						}
					}
				}
			}
			p.setZhongbiaojia(bid.getZbj());
		}
		return bid;
	}
	/***
	 * 标准测算价初始化
	 * @param p
	 * @return
	 * @throws Exception
	 */ 
	private Standard standardInit(Policy p) throws Exception{
		Standard sd = null;
		Map<String,Object> params = new HashMap<String,Object>();
		//先完整匹配
		params.put("province", p.getProvince());
		params.put("product", p.getProduct());
		params.put("pack", p.getPage());
		params.put("mode", p.getMode());
		params.put("qudao", p.getQudaolie());//条线
		params.put("ztype", p.getTerminaltype());//渠道
		params.put("stime", p.getXieyistarttime());//开始时间
		params.put("etime", p.getXieyiendtime());//结束时间
		
		Standard standard = iStandardService.getStandard(params);
		if (standard == null) {
			/***
			 * 标准测算价验证不通过，前台提示消息 
			 */
			Msg msg = new Msg(Constant.FAIL_CODE, 
					"省份：【"+p.getProvince()+"】，品种：【"+p.getProduct()+"】，"
					 + "包装：【"+p.getPage()+"】，模式：【"+p.getMode()+"】，"
					 + "条线：【"+p.getQudaolie()+"】，"
					 + "渠道：【"+p.getTerminaltype()+"】"
					 + "开始时间：【"+p.getXieyistarttime()+"】，结束时间：【"
					 + p.getXieyiendtime()+"】，未找到对应的标准测算价，请核查【标测库】");
			throw new Exception(msg.toString());
		}
		p.setBiaozhuncsdj(standard.getBzcsj());
		return sd;
	}
	/**
	 * 初始化协议
	 * 
	 * @param p 协议
	 * @param dto协议DTO
	 * @param request
	 * @param exitsID 是否初始化id
	 * @return
	 * @throws Exception
	 */
	private Policy initPolicy(Policy p, PolicyDTO dto, HttpServletRequest request, boolean exitsID) throws Exception {
		//初始化导入模板数据
		p.setByDTO(dto);
		//中标价初始化 
		bidInit(p);
		//标准测算价初始化 
		standardInit(p);

		// 协议资金成本 不空就使用用户录入的，为空则系统初始化 
		if (!StringUtil.isNotBlank(p.getZijingchengben())) {
			if (p.getQudaolie().contains("OTC") || p.getQudaolie().contains("大包") 
					|| p.getMode().contains("预付") || p.getMode().contains("虚拟") 
					|| p.getMode().contains("承包")) {
				p.setZijingchengben("0.00");
			} else {
				if (p.getProvince().contains("广东") || p.getProvince().contains("上海") 
						|| p.getProvince().contains("浙江")) {
					p.setZijingchengben("0.02");
				} else {
					p.setZijingchengben("0.03");
				}
			}
		}

		/**
		 * 协议测算价 协议测算价(底价)的计算公式 ---> 
		 * 有资金成本的算法：开票价-（推广费+发票服务费+达标奖励）/0.85-中标价*资金成本 (小包测算价要算资金成本率)
		 * 无资金成本的算法：开票价-（推广费+发票服务费+达标奖励）/0.85-0
		 */
		double sumMoney = Double.parseDouble(p.getTuiguangmoney()) 
				+ Double.parseDouble(p.getFapiaomoney())
				+ Double.parseDouble(p.getDaibiaomoney());// （1+3+4）
		/*** divisor=（推广费+发票服务费+达标奖励）/0.85 **/
		double divisor = 0;
		if (sumMoney != 0) {
			// 除法运算然后四舍五入保留4位小数
			double fv = 0.85;
			//2018年所有协议还是参考0.84的算法
			if(DateUtils.isDateGt2Eq("2019/01/01", p.getXieyiendtime())) {
				fv = 0.84;
			}
			divisor = ArithUtil.divide(sumMoney, fv, 4);
		}
		double kaipiaojia = Double.parseDouble(p.getKaipiaojia());
		double zbj = Double.parseDouble(p.getZhongbiaojia());
		double percent = Float.parseFloat(p.getZijingchengben());// 资金成本率
		double amassMoney = 0.0;
		if (p.getQudaolie().contains("OTC")) {
			amassMoney = kaipiaojia * percent;// 开票价*资金成本率
		} else {// Rx的协议测算价参考中标库的中标价来计算
			amassMoney = zbj * percent;// 中标价*资金成本率
		}
		double lastValue = ArithUtil.round(kaipiaojia-divisor-amassMoney,2);
		p.setDijia(lastValue + "");// 协议测算价
		

		/**
		 * 基础政策算法
		 * 协议的基础政策 = （推广费+发票服务费）/中标价 *100% 参考中标库来计算，若是OTC中标价改为开票价来计算
		 */
		DecimalFormat xydf = new DecimalFormat("0");
		double xybasicpolicy = 0;
		double xySumMoney = 0;
		//xySumMoney=1+3
		xySumMoney = Double.parseDouble(p.getTuiguangmoney())+Double.parseDouble(p.getFapiaomoney());
		if (p.getQudaolie().contains("OTC")) {
			if (xySumMoney>0 && kaipiaojia>0) {
				xybasicpolicy = ArithUtil.divide(xySumMoney,kaipiaojia,2)*100;// 除法运算并且保留2位小数
			}
		} else {
			if (xySumMoney>0 && zbj>0) {
				xybasicpolicy = ArithUtil.divide(xySumMoney,zbj,2)*100;// 除法运算并且保留2位小数
			}
		}
		p.setBasicpolicy(xydf.format(xybasicpolicy) + "%");
		//录入时间
		if(p.getId() == null) {
			p.setToday(DateUtils.dateToString(new Date(), "yyyy/MM/dd HH:mm:ss"));
		}
		//更新时间
		p.setMtime(new Date());
		//录入人员
		p.setZhongdiantubie(request.getSession().getAttribute("username").toString());
		return p;
	}

	@Override
	public void updateByParams(Map<String, Object> params,QueryVO vo,HttpServletRequest request) throws Exception {
		List<Policy> policys = policyMapper.selectPolicys(params);
		//获取查询条件，目的为了查询和该协议先关联的流向
		Set<String> yifan_parmas = new HashSet<String>();
		Set<String> product_parmas = new HashSet<String>();
		Set<String> pack_parmas = new HashSet<String>();

		Set<String> id3state = new HashSet<String>();
		
		String ps = vo.getStatus();
		for (Policy p : policys) {
			//如果协议状态的为3，即该协议已经废弃了，不准再对其操作
			if(p.getGuihuanriqi().equals("3")) {
				id3state.add(p.getId()+"");
			} else {
				p.setGuihuanriqi(ps);
				yifan_parmas.add(p.getQsterminal());
				product_parmas.add(p.getProduct());
				pack_parmas.add(p.getPage());
			}
		}
		if(!id3state.isEmpty()) {
			StringBuffer sb = new StringBuffer();
			for (String emsg : id3state) {
				sb.append(emsg+" ");
			}
			throw new Exception(sb.toString()+"，这些id对应的协议已经是3状态废弃的协议了，无法对其操作。");
		}
		//插入日志
		request.setAttribute("logAction", "E");
		policyLogService.insertByList(policys, request);
		
		//更新协议
		policyMapper.updateByList(policys);
		
		//更新缓存
		if("3".equals(ps)) {
			removeToContext(policys);
		} else {
			addToContext(policys);
		}
		
		//同步更新流向
		syncPlans(policys, yifan_parmas, product_parmas, pack_parmas);
	}

	@Override
	public void updatePlansByPolicys(List<Policy> list) throws Exception {
		syncPlans(list);
	}

}
